package com.yang.servlet;

import com.fasterxml.jackson.databind.JsonNode;
import com.yang.framework.RequestDispatcher;
import com.yang.po.Response;
import com.yang.utils.JsonUtil;
import com.yang.utils.RequestUtils;
import com.yang.utils.SpringUtils;
import com.yang.utils.StringUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.util.Assert;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import static com.yang.utils.ResponseUtils.response;

/**
 * @Description: mvc的servlet层
 * @author: Yang Qiang
 * @create: 2021-11-13 15:54
 */
@Slf4j
@WebServlet(name = "gateway", urlPatterns = "/yang/gateway")
public class YangServlet extends HttpServlet {

    // 当前类不会被spring管理, 所以我们要自己获取这个属性, 不能自动注入
    private RequestDispatcher requestDispatcher;

    @Override
    public void init() throws ServletException {
        requestDispatcher = SpringUtils.getBean("requestDispatcher");
//        super.init();
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 在这里拦截所有的请求
        // 1 获取当前时间
        long starTime = System.currentTimeMillis();

        // 2 获取requestID
        String requestId = StringUtil.getUUID();

        // 3 声明返回结果
        Response result = null;

        try {
            MDC.put("requestId", requestId);
            result = processRequest(req);
        }catch (Exception e){
            log.error(e.toString());
            result = Response.SYSTEM_FAIL(e.getMessage());
        }finally {
            result.put("requestId",requestId);
            response(resp,result.toJson());
            long endTime = System.currentTimeMillis();
            log.info("请求时长：{}",endTime - starTime);
            MDC.clear();;
        }

    }

    /**
     * 執行方法
     * @param req
     * @return
     */
    private Response processRequest(HttpServletRequest req) {
        // 获取请求参数
        String param = RequestUtils.getParam(req);
        // 获取请求头
        String header = RequestUtils.getHearders(req);
        // 获取请求的ip地址
        String clientIp = RequestUtils.getRemoteIp(req);
        log.info("=========param:{} , headers:{}===========",param,header);
        // TODO 增加IP黑名单，限流措施
        /*
            todo 限流: 比如我们设置一个方法每分钟只能调用10次,然后我们可以这样做, 把方法信息+时间作为一个key,
                方法信息+10:22 : 1
                调用次数作为value, 然后调用一次就加一, 然后我们每次调用的时候, 就先拿方法+当前分钟出来看一下这个value值是否已经达标了

         */
        /*
            todo 增加IP黑名单
                    这个就是拿到ip地址, 然后判断一下就行了
         */
        // 我们的参数可以将多个请求的参数合在一起发送，中间用|分割
        String[] params = param.split("\\|");
        // 这里是同步发送的方法，实际我们工作中会有异步的处理
        return sysProcessRequest(params,clientIp);
    }

    private Response sysProcessRequest(String[] params, String clientIp) {
        // 1、创建一个返回结果参数
        Map result = new HashMap<>();
        //2 、设置一个标识位，标识接口是否完全请求成功，因为有多个请求拼装再一起，
        // 可能有的成功，有的不能成功
        boolean isSuccess = true;
        for (String param : params) {
            JsonNode command = JsonUtil.getValue(param,"command");
            JsonNode method = JsonUtil.getValue(param, "method");
            Assert.notNull(command,"command不为空");
            Assert.notNull(method,"method不为空");
            String commandStr = command.asText();
            String methodStr = method.asText();
            Response apiResponse = requestDispatcher.dispatcher(commandStr,methodStr,param,clientIp);
            // 3、如果只有一个请求的话则直接返回
            if(params.length == 1){
                return apiResponse;
            }
            /*否则，将每个请求的结果组装成一个整体json返回给前端，key=command_method*/
            result.put(getKey(commandStr,methodStr),apiResponse.getResult());
            // 请求不成功则设置isSuccess和errorMsg
            if(isSuccess &  !apiResponse.isSuccess()){
                isSuccess = false;
                result.put("isSuccess",apiResponse.getIsSuccess());
                result.put("errorMSG",apiResponse.getErrorMSG());
            }
        }
        // 如果所有的请求都成功，则赋值 isSuccess = 0
        if(isSuccess){
            result.put("isSuccess","0");
        }
        return Response.SUCCESS().putAll(result);
    }

    private String getKey(String commandStr, String methodStr) {
        return StringUtil.join("_",commandStr,methodStr);
    }
}
